/*
 * 【注意】：C2001报错是由于没有使用UTF-8导致的，可以右击选择UTF-8 BOM on Save.
    2022-09-13  23:53  by  CYL
    目的：用于学习C++的抽象类（ABC），使用抽象类实现C++接口见demo1.
    【0】关于抽象类：
    A)如果类中含有至少一个函数被声明为纯虚函数，则这个类就是抽象类。
    B)抽象类不能直接被用于实例化对象，它只能作为“接口”使用，本身为一个最初基类。
    C)想要实例化抽象类，则必须以继承的方式先继承该抽象类，然后其子类去实现该抽象类中的所有纯虚函数。
    此时的子类成为具体类。

    【1】关于纯虚函数：
    A)纯虚函数是在基类中声明的虚函数，它在基类中没有定义，但要求任何派生类都要定义自己的实现方法。
    在基类中实现纯虚函数的方法是在虚函数原型后加"=0"
    https://www.runoob.com/w3cnote/cpp-virtual-function.html
*/
#include <iostream>
#include <string>
using namespace std;

class Shape{                    //【0-B】抽象类（基类）
public:
    //Shape();
    //~Shape();
    //当不存在内存操作时（如new、delete)，构造函数、析构函数可以不用写。
    virtual int getArea()=0;        //【0-A】【1】定义一个纯虚函数，在每个子类中必须被重写！
    virtual double getAreaF(){      //【2】定义一个虚函数，在每个子类中不一定要被重写。
        cout<<"这是一个Shape的虚函数！"<<endl;
        return 0;
    };
    void setLength(int Len)
    {
        Length = Len;
    }
    void setWidth(int Wid){
        Width = Wid;
    }
protected:
    int Length;
    int Width;
};
/*
    类的继承
*/
class Rectangle:public Shape{   //【0-C】具体类为抽象类的子类，即可将Shape视为一个模板。
public:
    int getArea(){              //【1】
        int result = this->Width * this->Length;
        cout<<"长方形的面积为："<<result<<endl;
        return result;
    }
};
/*
    类的继承
*/
class Triangle:public Shape{    //【0-C】具体类为抽象类的子类，即可将Shape视为一个模板。
public:
    int getArea(){              //【1】【注意】纯虚函数在每个子类中必须被重写！
        cout<<"请使用getAreaF()"<<endl;
        return -1;
    }
    double getAreaF(){          //【2】【注意】虚函数在每个子类中不一定要被重写！在Triangle中被重写了，但在Rectangle中没有重写！
        double result = this->Width * this->Length / 2.0;
        cout<<"三角形的面积为："<<result<<endl;
        return result;
    }

};
int main()
{
    Rectangle Rect0;            //【0-C】
    Rect0.setLength(5);
    Rect0.setWidth(5);
    Rect0.getArea();            //【1】纯虚函数必须被重写！
    Rect0.getAreaF();           //【2】虚函数在Rectangle中没有重写！

    Triangle Tri0;              //【0-C】
    Tri0.setLength(5);
    Tri0.setWidth(5);
    Tri0.getArea();             //【1】纯虚函数必须被重写！
    Tri0.getAreaF();            //【2】虚函数在Triangle中被重写了！

    return 0;
}
